package org.flexthinker.binding.value.support
{
    import org.flexthinker.binding.value.PropertyChangeListener;
    import org.flexthinker.binding.value.ValueModel;

    import mx.events.PropertyChangeEvent;

    import org.hamcrest.assertThat;
    import org.hamcrest.object.equalTo;

    /**
     *
     */
    public class ValueHolderTest
    {
        private var mockBean:MockBean;
        private var vh:ValueModel;
        private var listener:PropertyChangeListenerCounter;

        public function ValueHolderTest()
        {
        }

        [Before]
        public function setUp():void
        {
            mockBean = new MockBean();
            listener = new PropertyChangeListenerCounter();
        }

        [Test]
        public function testValueChangeListeners():void
        {
            vh = new ValueHolder(mockBean,"bindableProperty");
            vh.addValueChangeListener( listener );
            assertThat("listener should have NOT been called", listener.counter, equalTo(0));
            assertThat("value holder has the wrong value", vh.getValue(), equalTo(null));
            mockBean.bindableProperty = "SOME STRING";
            assertThat("listener should have been called", listener.counter, equalTo(1));
            assertThat("value holder has the wrong value", vh.getValue(), equalTo(mockBean.bindableProperty));

            vh.removeValueChangeListener( listener );
            mockBean.bindableProperty = "NEW STRING";
            assertThat("listener should have NOT been called", listener.counter, equalTo(1));
        }

        [Test]
        public function testValueChangeListenerOnCustomBindableProp():void
        {
            mockBean.bindablePropertyWithCustomEvent = "INITIAL";
            vh = new ValueHolder( mockBean,"bindablePropertyWithCustomEvent");
            assertThat("valueHolder should already hold the value", vh.getValue(), equalTo(mockBean.bindablePropertyWithCustomEvent) );

            vh.addValueChangeListener( listener );
            var localListener:PropertyChangeListener =  new DelegatingPropertyChangeListener(
                function(event:PropertyChangeEvent):void
                {
                    //even when a custom event is used with [Bindable], the lib make sure the old value is sent anyway.
                    assertThat("oldValue sholdn't be null for custom events", event.oldValue, equalTo("INITIAL"));
                    assertThat("newValue is wrong", event.newValue, equalTo("FIRST"));
                }
                );
            vh.addValueChangeListener( localListener );

            mockBean.bindablePropertyWithCustomEvent = "FIRST";

            assertThat("listener should have been called", listener.counter, equalTo(1));
            assertThat("valueHolder should return the actual value", vh.getValue(), equalTo("FIRST"));

            vh.removeValueChangeListener( localListener );
            vh.setValue( "SECOND_FROM_VH");
            assertThat("listener should have been called", listener.counter, equalTo(2));
            assertThat("mockBean should have had the same value with the value holder", mockBean.bindablePropertyWithCustomEvent, equalTo(vh.getValue()));
            assertThat("mockBean should have been updated", mockBean.bindablePropertyWithCustomEvent, equalTo("SECOND_FROM_VH"));
        }

        [Test]
        public function testWithIntType():void
        {
            mockBean.simpleInt = 10;
            vh = new ValueHolder( mockBean,"simpleInt");
            assertThat("valueHolder should already hold the int value", vh.getValue(), equalTo(mockBean.simpleInt) );

            vh.addValueChangeListener( listener );
            var localListener:PropertyChangeListener =  new DelegatingPropertyChangeListener(
                function(event:PropertyChangeEvent):void
                {
                    //even when a custom event is used with [Bindable], the lib make sure the old value is sent anyway.
                    assertThat("oldValue sholdn't be null", event.oldValue, equalTo(10));
                    assertThat("newValue is wrong", event.newValue, equalTo(20));
                }
                );
            vh.addValueChangeListener( localListener );

            mockBean.simpleInt = 20;
            assertThat("listener should have been called", listener.counter, equalTo(1));
            assertThat("valueHolder should return the actual value", vh.getValue(), equalTo(20));

            vh.removeValueChangeListener( localListener );
            vh.setValue(30);
            assertThat("listener should have been called", listener.counter, equalTo(2));
            assertThat("mockBean should have had the same value with the value holder", mockBean.simpleInt, equalTo(vh.getValue()));
            assertThat("mockBean should have been updated", mockBean.simpleInt, equalTo(30));
        }

        [Test]
        public function testWithBooleanType():void
        {
            mockBean.simpleBoolean = true;
            vh = new ValueHolder( mockBean,"simpleBoolean");
            assertThat("valueHolder should already hold the Boolean value", vh.getValue(), equalTo(mockBean.simpleBoolean) );

            vh.addValueChangeListener( listener );
            var localListener:PropertyChangeListener =  new DelegatingPropertyChangeListener(
                function(event:PropertyChangeEvent):void
                {
                    //even when a custom event is used with [Bindable], the lib make sure the old value is sent anyway.
                    assertThat("oldValue sholdn't be null", event.oldValue, equalTo(true));
                    assertThat("newValue is wrong", event.newValue, equalTo(false));
                }
                );
            vh.addValueChangeListener( localListener );

            mockBean.simpleBoolean = false;
            assertThat("listener should have been called", listener.counter, equalTo(1));
            assertThat("valueHolder should return the actual value", vh.getValue(), equalTo(false));

            vh.removeValueChangeListener( localListener );
            vh.setValue(true);
            assertThat("listener should have been called", listener.counter, equalTo(2));
            assertThat("mockBean should have had the same value with the value holder", mockBean.simpleBoolean, equalTo(vh.getValue()));
            assertThat("mockBean should have been updated", mockBean.simpleBoolean, equalTo(true));
        }
    }
}